package org.zjx.swing.model;

import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import lombok.Data;
import org.zjx.dom4j.XmlUtils;
import org.zjx.entity.LiterateSubScreenBean;
import org.zjx.swing.bean.*;
import org.zjx.swing.bean.Font;
import org.zjx.swing.font.FontUtil;
import org.zjx.swing.font.LiterateUtil;
import org.zjx.swing.font.WordOperate;
import org.zjx.util.FileUtil;
import org.zjx.util.ImageUtil;
import org.zjx.util.WordBeanUtil;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Data
public class LiterateModel {
    private String path; //图片路径
    private BufferedImage screen;
    private List<LiterateSubScreenBean> subScreenBeans;
    private WinDef.RECT subScreenRect; //截取范围
    private List<FontFilePath> fontFilePaths = new ArrayList<>();
    private List<ColorRecord> colorRecords = new ArrayList<>();
    private List<List<WordBean>> wordBeans;
    private WordOperate wordOperate;
    private int mergeSize = 0;
    private WordBean nowWordBean; //当前选中/合并的数据
    private Robot robot;
    private int fontHeight;

    public LiterateModel() {
        subScreenBeans = new ArrayList<LiterateSubScreenBean>();
        subScreenBeans.add(new LiterateSubScreenBean("原图", ImageUtil.getRect(0, 0, 0, 0)));
        subScreenBeans.add(new LiterateSubScreenBean("地标", ImageUtil.getRect(11, 25, 137, 40)));
        subScreenBeans.add(new LiterateSubScreenBean("NPC名字", ImageUtil.getRect(178, 266, 276, 286)));
        subScreenBeans.add(new LiterateSubScreenBean("NPC内容", ImageUtil.getRect(142, 293, 657, 460)));
        subScreenBeans.add(new LiterateSubScreenBean("任务", ImageUtil.getRect(639, 138, 795, 310)));

        List<String> classPath = new ArrayList<>();
        classPath.add("org.zjx.swing.bean");
        XmlUtils.setSimpleClassName(true,classPath);
    }

    public BufferedImage getSubImage() {
        return ImageUtil.subImage(screen, subScreenRect);
    }

    public void setFontFilePathsChecked(int index) {
        for (FontFilePath fontFilePath : fontFilePaths) {
            fontFilePath.setChecked(false);
        }
        fontFilePaths.get(index).setChecked(true);
    }

    public void setColorListChecked(int index) {
        colorRecords.get(index).setChecked(!colorRecords.get(index).isChecked());
    }

    public void deleteColorList() {
        colorRecords.removeIf(ColorRecord::isChecked);
    }

    private String checkedFondFilePath() {
        for (FontFilePath fontFilePath : fontFilePaths) {
            if (fontFilePath.isChecked()) {
                return fontFilePath.getFontPath();
            }
        }
        return null;
    }


    public BufferedImage getGameScreen() {
        List<WinDef.HWND> hwnds = getHwndS("WSGAME",null);
        if (hwnds.isEmpty()) return null;
        if (robot == null) {
            try {
                robot = new Robot();
            } catch (AWTException e) {
                throw new RuntimeException(e);
            }
        }

        WinDef.RECT rect = new WinDef.RECT();
        User32.INSTANCE.GetWindowRect(hwnds.get(0), rect);
        rect.top = rect.top + 31;
        rect.left = rect.left + 8;
        rect.right = rect.right - 8;
        rect.bottom = rect.bottom - 8;
        screen = robot.createScreenCapture(rect.toRectangle());
        return screen;
    }


    public static List<WinDef.HWND> getHwndS(String className, String titleName) {
        List<WinDef.HWND> hs= new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            WinDef.HWND before = null;
            if(!hs.isEmpty()) before = hs.get(hs.size()-1);
            WinDef.HWND hwnd1 = User32.INSTANCE.FindWindowEx(null,before,className, titleName);
            if (hwnd1 != null) {
                hs.add(hwnd1);
            }
        }
        return hs;
    }


    //TODO 识别
    public String recognize() {
        List<Color> colors = gatherColors();
        String fontPath = checkedFondFilePath();
        if (screen == null || subScreenRect == null || colors.isEmpty() || Objects.requireNonNull(fontPath).isEmpty())
            return null;

        try {
            String xml = FileUtil.readFile(fontPath);
            XmlFonts xmlFonts = XmlUtils.xmlToObject(xml, XmlFonts.class);

            wordBeans = LiterateUtil.identify(ImageUtil.subImage(screen, subScreenRect), fontHeight, colors);


            ParagraphBean.Categories categories = FontUtil.categories("", colors, ImageUtil.subImage(screen, subScreenRect), xmlFonts.getFonts(), fontHeight);

            StringBuilder stringBuilder = new StringBuilder();
            for (ParagraphBean.Word word : categories.getWords()) {
                stringBuilder.append(word.getName())
                        .append(" ")
                        .append(word.getRect())
                        .append("\n");
            }
            System.out.println(System.currentTimeMillis() + "MODEL识别");
            return stringBuilder.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    public WordBean recognizeImage() throws Exception {
        List<Color> colors = gatherColors();
        if (screen == null || subScreenRect == null || colors.isEmpty()) return null;

        wordBeans = LiterateUtil.identify(ImageUtil.subImage(screen, subScreenRect), fontHeight, colors);

        wordOperate = new WordOperate(wordBeans, null);

        mergeSize = 0;
        nowWordBean = wordOperate.getNextWord();
        return nowWordBean;
    }

    public WordBean nextWord() throws Exception {
        if (wordOperate == null || wordBeans == null || wordBeans.isEmpty()) return null;
        mergeSize = 0;
        nowWordBean = wordOperate.getNextWord();
        return nowWordBean;
    }

    public WordBean prevWord() throws Exception {
        if (wordOperate == null || wordBeans == null || wordBeans.isEmpty()) return null;
        mergeSize = 0;
        nowWordBean = wordOperate.getPrevWord();
        return nowWordBean;
    }

    public WordBean mergeWord() throws Exception {
        if (wordOperate == null || wordBeans == null || wordBeans.isEmpty()) return null;
        mergeSize++;
        nowWordBean = wordOperate.merge(mergeSize);
        return nowWordBean;
    }

    public String getWordBeanName(WordBean wordBean) {
        String fontPath = checkedFondFilePath();
        try {
            XmlFonts xmlFonts =null;
            String xml = FileUtil.readFile(fontPath);
            if (xml.isEmpty()) {
                XmlFonts xmlFonts1 = WordBeanUtil.wordBeanToXmlFonts(wordBean);
                String s = XmlUtils.objectToXml(xmlFonts1);
                FileUtil.saveXmlToFile(s,fontPath);
                xmlFonts = XmlUtils.xmlToObject(s, XmlFonts.class);
            } else {
                xmlFonts = XmlUtils.xmlToObject(xml, XmlFonts.class);
            }
            return FontUtil.matching(wordBean,xmlFonts.getFonts());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void updateValue(String value) {

        String fontPath = checkedFondFilePath();
        try {
            String xml = FileUtil.readFile(fontPath);
            List<Font> fonts;
            if (xml.isEmpty()) {
                fonts = new ArrayList<>();
            } else {
                XmlFonts xmlFonts = XmlUtils.xmlToObject(xml, XmlFonts.class);
                fonts = xmlFonts.getFonts();
            }

            Font sameFont = haveSameFont(fonts, FontUtil.arrayToString(nowWordBean.getBlock()));
            if (sameFont != null) {
                sameFont.setName(value);
            } else {
                Font font = new Font();
                font.setName(value);
                font.setBlock(FontUtil.arrayToString(nowWordBean.getBlock()));
                font.setWide(nowWordBean.getWith());
                font.setHigh(nowWordBean.getHeight());
                fonts.add(font);
            }

            XmlFonts xmlFonts = new XmlFonts();
            xmlFonts.setFonts(fonts);

            xml = XmlUtils.objectToXml(xmlFonts);
            FileUtil.saveXmlToFile(xml, fontPath);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private Font haveSameFont(List<Font> fonts, String block) {
        for (Font font : fonts) {
            if (font.getBlock().equals(block)) return font;
        }
        return null;
    }

    private List<Color> gatherColors() {
        List<Color> colors = new ArrayList<>();
        for (ColorRecord record : colorRecords) {
            if (!record.isChecked()) continue;
            // 计算红色、绿色、蓝色分量的取值范围
            for (int dr = -record.getDeviationR(); dr <= record.getDeviationR(); dr++) {
                for (int dg = -record.getDeviationG(); dg <= record.getDeviationG(); dg++) {
                    for (int db = -record.getDeviationB(); db <= record.getDeviationB(); db++) {
                        // 计算最终的红色、绿色和蓝色值
                        int finalR = Math.min(255, Math.max(0, record.getR() + dr));
                        int finalG = Math.min(255, Math.max(0, record.getG() + dg));
                        int finalB = Math.min(255, Math.max(0, record.getB() + db));

                        // 创建新的 Color 对象
                        Color color = new Color(finalR, finalG, finalB);
                        colors.add(color);
                    }
                }
            }
        }
        return colors;
    }

}
